/*
 * Created on Mar 7, 2005
 */
package org.scohen.juploadr.uploadapi.flickrrest.ui;

import java.text.DecimalFormat;
import java.util.Iterator;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.scohen.juploadr.app.tags.TagParser;
import org.scohen.juploadr.prefs.BaseConfigurationForm;
import org.scohen.juploadr.prefs.Configuration;
import org.scohen.juploadr.prefs.Fault;
import org.scohen.juploadr.ui.MessageUtils;
import org.scohen.juploadr.uploadapi.Account;
import org.scohen.juploadr.uploadapi.CommunicationException;
import org.scohen.juploadr.uploadapi.ImageUploadApi;
import org.scohen.juploadr.uploadapi.ProtocolException;
import org.scohen.juploadr.uploadapi.flickrrest.Messages;
import org.scohen.juploadr.uploadapi.flickrrest.RestFlickrApi;
import org.scohen.juploadr.uploadapi.flickrrest.authentication.FlickrAccount;
import org.scohen.juploadr.util.ConversionUtils;

public class FlickrForm extends BaseConfigurationForm {
    private static final DecimalFormat percentFormat = new DecimalFormat("####0.##%"); //$NON-NLS-1$
    private Label accountTypeLabel;
    private Label accountType;
    private Label downloadLimitLabel;
    private Label downloadLimit;
    private Label authorizeLabel;
    private Button authorize;
    private Label accountsLabel;
    private Combo accounts;
    private Button deleteAccount;
    private Button addAnotherAccount;
    private Label addAnotherAccountLabel;

    public FlickrForm(Composite parent) {
        super(parent);
    }

    /**
     * 
     */
    protected void initUI() {
        GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        layout.horizontalSpacing = 5;
        this.setLayout(layout);

        if (api.isCurrentAccountAuthenticated()) {
            initAuthorizedComponents();
        }
        authorizeLabel = new Label(this, SWT.NONE);
        authorizeLabel.setText(""); //$NON-NLS-1$
        authorize = new Button(this, SWT.PUSH);
        authorize.setImage(api.getIcon());
        if (!api.isCurrentAccountAuthenticated()) {
            authorize.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.CENTER));
        }
        authorize.setText(Messages.getString("juploadr.ui.button.validate.settings")); //$NON-NLS-1$
        authorize.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                FlickrForm.this.reauthAccount();
            }
        });

        addAnotherAccountLabel = new Label(this, SWT.NONE);
        addAnotherAccountLabel.setText(""); //$NON-NLS-1$
        if (!ImageUploadApi.getInstance().isCurrentAccountNullAccount()) {
            addAnotherAccount = new Button(this, SWT.PUSH);
            addAnotherAccount.setText(org.scohen.juploadr.uploadapi.flickrrest.Messages
                    .getString("juploadr.ui.flickrrest.flickrform.addaccount")); //$NON-NLS-1$
            addAnotherAccount.addMouseListener(new MouseAdapter() {
                public void mouseUp(MouseEvent event) {
                    FlickrAccount account = (FlickrAccount) api.newAccount("--"); //$NON-NLS-1$
                    FlickrForm.this.authorizeAccount(account, true);
                }
            });
        }
        addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent event) {
                FlickrForm.this.disposed(event);
            }
        });
    }

    /**
     * 
     */
    private void initAuthorizedComponents() {
        FlickrAccount currentAccount = (FlickrAccount) api.getCurrentAccount();
        accountsLabel = new Label(this, SWT.NONE);
        accountsLabel.setText(Messages.getString("juploadr.ui.label.username")); //$NON-NLS-1$
        Composite accountComp = new Composite(this, SWT.NONE);
        GridLayout layout = new GridLayout(2, false);

        GridData data = new GridData(GridData.FILL_HORIZONTAL);
        accountComp.setLayoutData(data);
        accountComp.setLayout(layout);

        accounts = new Combo(accountComp, SWT.DROP_DOWN | SWT.READ_ONLY);
        accounts.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        
        int i = 0;
        for(Account account: FlickrAccount.allAccounts().values()){
            accounts.add(account.getName());
            if (account.equals(currentAccount)) {
                accounts.select(i);
            }
            i++;
        }

        accounts.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {
                if (event.doit) {
                    Combo combo = (Combo) event.widget;

                    String accountName = combo.getItem(combo.getSelectionIndex());
                    FlickrAccount account = (FlickrAccount) FlickrAccount.allAccounts().get(accountName);
                    FlickrForm.this.api.setCurrentAccount(account);
                    try {
                        api.authenticate(account);
                    } catch (ProtocolException e) {
                        // this shouldn't happen because the account should
                        // already be authenticated
                        e.printStackTrace();
                    } catch (CommunicationException e) {
                        MessageUtils.showErrorMessage(org.scohen.juploadr.Messages
                                .getString("juploadr.ui.dialog.error.communication") //$NON-NLS-1$
                                + e.getMessage());
                    }
                    accountChanged(account);
                }
            }
        });

        deleteAccount = new Button(accountComp, SWT.PUSH);
        deleteAccount.setText("Delete");
        deleteAccount.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                String accountName = accounts.getItems()[accounts.getSelectionIndex()];
                if (MessageUtils.showMessage(org.scohen.juploadr.Messages.getString(
                        "juploadr.ui.confirm.delete.account", accountName, ImageUploadApi.getInstance().getSiteName()), org.scohen.juploadr.Messages
                        .getString("org.juploadr.ui.confirm.delete.label"), SWT.YES | SWT.NO)) {
                    Account account = (Account) FlickrAccount.allAccounts().get(accountName);
                    account.delete();
                    List allAccounts = RestFlickrApi.getInstance().allAccounts();
                    FlickrAccount changedAccount = FlickrAccount.getNullAccount();
                    if (!allAccounts.isEmpty()) {
                        changedAccount = (FlickrAccount) allAccounts.get(0);
                    }
                    RestFlickrApi.getInstance().setCurrentAccount(changedAccount);
                    FlickrForm.this.accountChanged(changedAccount);
                }
            }
        });

        accountTypeLabel = new Label(this, SWT.NONE);
        accountType = new Label(this, SWT.NONE);
        accountTypeLabel.setText(Messages.getString("juploadr.ui.label.accounttype")); //$NON-NLS-1$
        setAccountType(currentAccount);

        downloadLimitLabel = new Label(this, SWT.NONE);
        downloadLimit = new Label(this, SWT.NONE);
        downloadLimit.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        downloadLimitLabel.setText(Messages.getString("juploadr.ui.label.montly.limit")); //$NON-NLS-1$
        updateLimits();

    }

    /**
     * @param currentAccount
     */
    private void setAccountType(FlickrAccount currentAccount) {
        if (accountType != null && !accountType.isDisposed()) {
            accountType
                    .setText(currentAccount.isPro() ? Messages.getString("juploadr.ui.account.pro") : Messages.getString("juploadr.ui.account.free")); //$NON-NLS-1$ //$NON-NLS-2$
        }
    }

    /**
     * 
     */
    private void updateLimits() {
        FlickrAccount currentAccount = (FlickrAccount) api.getCurrentAccount();
        if (currentAccount.isAuthenticated()) {
            StringBuffer limitText = new StringBuffer();
            if (currentAccount.isUnlimited()) {
                limitText.append(Messages.getString("juploadr.ui.label.accounttype.unlimited")); //$NON-NLS-1$
            } else {

                limitText.append(ConversionUtils.bytesToHumanReadable(currentAccount.getCurrentUploadUsed()));
                limitText.append("/"); //$NON-NLS-1$
                limitText.append(ConversionUtils.bytesToHumanReadable(currentAccount.getMonthlyUploadLimit()));
                limitText.append(" ("); //$NON-NLS-1$
                if (currentAccount.getMonthlyUploadLimit() > 0) {
                    limitText.append(percentFormat.format(((double) currentAccount.getCurrentUploadUsed())
                            / ((double) currentAccount.getMonthlyUploadLimit())));
                } else {
                    limitText.append(percentFormat.format(0));
                }
                limitText.append(")"); //$NON-NLS-1$
            }
            downloadLimit.setText(limitText.toString());
        }
    }

    public void saveChanges() {
    }

    public Fault validateChanges() {

        return null;
    }

    public String getFormName() {
        return Messages.getString("juploadr.ui.flickrform.title"); //$NON-NLS-1$
    }

    private void reauthAccount() {
        Fault errors = validateChanges();
        if (errors != null) {
            MessageUtils.showErrorMessage(errors.getText());
        } else {
            boolean shouldRedraw = !api.isCurrentAccountAuthenticated();

            FlickrAccount userInfo = (FlickrAccount) api.getCurrentAccount();
            userInfo.setAuthenticated(false);
            authorizeAccount(userInfo, shouldRedraw);
        }
    }

    /**
     * @param account
     * @param shouldRedraw
     * @param flickrApi
     */
    private void authorizeAccount(FlickrAccount account, boolean shouldRedraw) {
        Configuration config = Configuration.getInstance();

        if (!config.hasUpgraded()) {
            // if they're previous flickr users, try to upgrade
            // their account
            account.setToken(config.getOldToken());
            account.setUsername(config.getOldUsername());
            account.setAuthenticated(account.getToken().length() > 0);

        }

        try {

            if (api.authenticate(account)) {
                account.setDefaultPrivacySetting(config.getDefaultPrivacySetting());
                account.setDefaultTags(TagParser.parse(config.getDefaultTags()));
                config.upgradeComplete();

                if (shouldRedraw) {
                    accountChanged(account);

                } else {
                    // they still aren't authenticated, and auth threw no
                    // exceptions. They cancelled?
                    // do nothing.

                }
                MessageUtils.showInfoMessage(Messages.getString("juploadr.ui.dialog.account.info.correct")); //$NON-NLS-1$
            }
        } catch (ProtocolException e) {
            MessageUtils.showErrorMessage(Messages.getString("juploadr.ui.dialog.error.invalid.credentials")); //$NON-NLS-1$
            Account defaultAccount = api.getCurrentAccount();
            if (defaultAccount == null) {
                defaultAccount = FlickrAccount.getNullAccount();
            }
            api.setCurrentAccount(defaultAccount);
        } catch (CommunicationException e) {
            MessageUtils.showErrorMessage(org.scohen.juploadr.Messages
                    .getString("juploadr.ui.dialog.error.communication") //$NON-NLS-1$
                    + e.getMessage());
        }
    }

    /**
     * @param account
     */
    private void accountChanged(FlickrAccount account) {
        resetUI();
        initUI();
        setAccountType(account);
        account.save();
        this.layout();
        parent.accountChanged();
    }

    public void accountChanged() {

    }

    private void disposed(DisposeEvent event) {
        if (api.isCurrentAccountAuthenticated()) {
            accountType.dispose();
            accountTypeLabel.dispose();
            downloadLimit.dispose();
            downloadLimitLabel.dispose();
            accounts.dispose();
            accountsLabel.dispose();
        }

        authorize.dispose();
        authorizeLabel.dispose();
        if (addAnotherAccount != null) {
            addAnotherAccount.dispose();
            addAnotherAccountLabel.dispose();
        }
    }

}